import { useUserStore } from '@/stores/user'
import { reactive, watchEffect } from 'vue'
import { routes } from '@/router/routes'
import { Role } from '@/constants/role'

import type { RouteMeta, RouteRecordRaw } from 'vue-router'

type MenuRoute = {
  name: string
  title: string
  icon: string
  role: Role
  requireAuth: boolean
  children?: MenuRoute[]
}

export type MenuTree = {
  title: string
  name: string
  icon: string
  children?: MenuTree[]
}

export function useMenuTree() {
  const userStore = useUserStore()
  const menuRoutes: MenuRoute[] = transformRoutes(routes)
  const menuTree = reactive<MenuTree[]>([])
  const buildMenuTree = (menuRoutes: MenuRoute[]): MenuTree[] => {
    return menuRoutes
      .filter(
        ({ requireAuth, role }) => !requireAuth || (userStore.hasLogin && userStore.isEnabled(role))
      )
      .map<MenuTree>(({ children, ...rest }) => ({
        ...rest,
        children: children && buildMenuTree(children)
      }))
  }

  watchEffect(() => menuTree.splice(0, menuTree.length, ...buildMenuTree(menuRoutes)))

  return { menuTree }
}

function transformRoutes(routes: RouteRecordRaw[]): MenuRoute[] {
  routes.sort((a, b) => (b.meta?.order ?? 0) - (a.meta?.order ?? 0))

  return routes.reduce<MenuRoute[]>((parsedRoutes, route) => {
    if (import.meta.env.DEV) {
      checkRoute(route)
    }

    const {
      hideInMenu = false,
      hideChildrenInMenu = false,
      requireAuth = false,
      role = Role.All,
      menuTitle: title = '',
      icon = ''
    } = route.meta ?? ({} as RouteMeta)

    if (hideInMenu) {
      return hideChildrenInMenu || !route.children
        ? parsedRoutes
        : parsedRoutes.concat(...transformRoutes(route.children))
    }

    return parsedRoutes.concat({
      name: route.name as string,
      title,
      icon,
      role,
      requireAuth,
      children: hideChildrenInMenu ? undefined : route.children && transformRoutes(route.children)
    })
  }, [])
}

function checkRoute(route: RouteRecordRaw) {
  const routeName = (route.name as string) || route.path

  if (route.meta === undefined) {
    console.warn(`Route ${routeName} has no meta property`)
    return
  }

  if (route.meta.requireAuth === undefined) {
    console.warn(`Route ${routeName} has no requiresAuth property`)
  }

  if (route.meta.role === undefined) {
    console.warn(`Route ${routeName} has no role property`)
  }

  if (route.meta.menuTitle === undefined && !route.meta.hideInMenu) {
    console.warn(`Route ${routeName} has no title property, but is not hidden in menu`)
  }
}
